#ifndef MAP_H
#define MAP_H

#include "KeyPoseFrame.h"

#include <set>
#include <list>
#include <pangolin/pangolin.h>
#include <mutex>

#include <boost/serialization/base_object.hpp>

namespace msf
{
class KeyPoseFrame;
class Atlas;

class Map
{
      friend class boost::serialization::access;

      template<class Archive>
      void serialize(Archive &ar, const unsigned int version)
      {
            ar & mnId;
            ar & mnInitKPFid;
            ar & mnMaxKPFid;
            ar & mnBigChangeIdx;

            // Save/load a set structure, the set structure is broken in libboost 1.58 for ubuntu 16.04, a vector is serializated
            //ar & mspKeyFrames;
            //ar & mspMapPoints;
            ar & mvpBackupKeyPoseFrames;
            //ar & mvpBackupMapPoints;

            ar & mvBackupKeyPoseFrameOriginsId;

            ar & mnBackupKPFinitialID;
            ar & mnBackupKPFlowerID;

            ar & mbImuInitialized;
            ar & mbIsInertial;
            ar & mbIMU_BA1;
            ar & mbIMU_BA2;
      }

public:
      EIGEN_MAKE_ALIGNED_OPERATOR_NEW
      Map();
      Map(int initKPFid);
      ~Map();

      void AddKeyPoseFrame(KeyPoseFrame* pKPF);
      void EraseKeyPoseFrame(KeyPoseFrame* pKPF);
      void InformNewBigChange();
      int GetLastBigChangeIdx();

      std::vector<KeyPoseFrame*> GetAllKeyPoseFrames();
      
      long unsigned KeyPoseFramesInMap();

      long unsigned int GetId();

      long unsigned int GetInitKPFid();
      void SetInitKPFid(long unsigned int initKPFif);
      long unsigned int GetMaxKPFid();

      KeyPoseFrame* GetOriginKPF();

      void SetCurrentMap();
      void SetStoredMap();

      bool HasThumbnail();
      bool IsInUse();

      void SetBad();
      bool IsBad();

      void clear();

      int GetMapChangeIndex();
      void IncreaseChangeIndex();
      int GetLastMapChange();
      void SetLastMapChange(int currentChangeId);

      void SetImuInitialized();
      bool isImuInitialized();

      void ApplyScaledRotation(const Sophus::SE3f &T, const float s, const bool bScaledVel=false);

      void SetInertialSensor();
      bool IsInertial();
      void SetIniertialBA1();
      void SetIniertialBA2();
      bool GetIniertialBA1();
      bool GetIniertialBA2();

      //void PrintEssentialGraph();
      //bool CheckEssentialGraph();
      void ChangeId(long unsigned int nId);

      unsigned int GetLowerKPFID();
      //void PreSave(std::set<GeometricCamera*> &spCams);
      //void PostLoad(KeyFrameDatabase* pKFDB, ORBVocabulary* pORBVoc/*, map<long unsigned int, KeyFrame*>& mpKeyFrameId*/, map<unsigned int, GeometricCamera*> &mpCams);

      void printReprojectionError(std::list<KeyPoseFrame*> &lpLocalWindowKPFs, KeyPoseFrame* mpCurrentKPF, std::string &name, std::string &name_folder);

      std::vector<KeyPoseFrame*> mvpKeyPoseFrameOrigins;
      std::vector<unsigned long int> mvBackupKeyPoseFrameOriginsId;
      KeyPoseFrame* mpFirstRegionKPF;
      std::mutex mMutexMapUpdate;

      // This avoid that two points are created simultaneously in separate threads (id conflict)
      std::mutex mMutexPointCreation;

      bool mbFail;

      static long unsigned int nNextId;

      // DEBUG: show KPFs which are used in LBA
      std::set<long unsigned int> msOptKPFs;
      std::set<long unsigned int> msFixedKPFs;

protected:

      long unsigned int mnId;

      std::set<KeyPoseFrame*> mspKeyPoseFrames;

      // Save/load, the set structure is broken in libboost 1.58 for ubuntu 16.04, a vector is serializated
      std::vector<KeyPoseFrame*> mvpBackupKeyPoseFrames;

      KeyPoseFrame* mpKPFinitial;
      KeyPoseFrame* mpKPFlowerID;

      unsigned long int mnBackupKPFinitialID;
      unsigned long int mnBackupKPFlowerID;

      bool mbImuInitialized;

      int mnMapChange;
      int mnMapChangeNotified;

      long unsigned int mnInitKPFid;
      long unsigned int mnMaxKPFid;

      // 地图上大改变相关的下标 (loop closure, global BA)
      int mnBigChangeIdx;

      // View of the map in aerial sight (for the AtlasViewer)
      GLubyte* mThumbnail;

      bool mIsInUse;
      bool mHasTumbnail;
      bool mbBad = false;

      bool mbIsInertial;
      bool mbIMU_BA1;
      bool mbIMU_BA2;

      // Mutex
      std::mutex mMutexMap;
};

} //namespace msf


#endif //MAP_H